using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.DataAccess.Common;
using T.FAS.Runtime.DataAccess.Kernel;
using T.FAS.Runtime.DataAccess.SPI;
using T.FAS.Runtime.DataAccess.SQLDom;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.Kernel.Service;

namespace T.FAS.Runtime.DataAccess.Engine
{
    class CDODataQueryService : IQueryService<CompositeDataObject>
    {
        public event ExecuteDataAccessAction Execute;
        public event BuildDataAccessActionContext BuildContext;
        private readonly IDatabase _db = DatabaseFactory.CreateDefaultDatabase();
        private readonly IDACLogService _localLogService = DACLogFactory.GetDACLogService();
        private readonly OpeType _opeType = OpeType.Retrieve;

        /// <summary>
        /// CDO查询指定主键id的数据
        /// </summary>
        /// <param name="metadata">元数据</param>
        /// <param name="dataId">数据唯一标识</param>
        /// <param name="extParams">额外控制参数</param>
        /// <returns>通用结果对象</returns>
        public TResult QueryData(CompositeDataObject metadata, string dataId, Dictionary<string, object> extParams = null)
        {
            RpcContext.Current.Increase();
            if (metadata == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_MetaDataCannotBeNull);
            if (string.IsNullOrWhiteSpace(dataId))
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_DataIDCannotBeNull);

            DateTime start = DateTime.Now;
            Exception ex = null;

            try
            {
                //获取控制上下文
                SqlExecuteControlContext controlContext = DACControlContextHelper.GetDefaultControlContext(extParams, metadata);

                //解析生成SQL
                var sqls = SQLBuilderFactory.CreateCDOSQLBuilder().ParseQuerySqlByID(metadata, dataId, controlContext);

                //执行SQL
                var datatable = ExecuteSQL(metadata, sqls);

                //获取结果
                var result = TResultConverter.ConvertToTResultFromCDO(metadata, datatable, false);
                return result;
            }
            catch (Exception e)
            {
                var msg = $"CDO:{metadata.Code}执行Query异常，msg:{e.Message}";
                _localLogService.WriteError(e, msg);
                ex = new Exception(msg, e);
                CDOMonitor.RootCaseReport(metadata, start, ex, _opeType);
                throw ex;
            }
            finally
            {
                CDOMonitor.MonitorTPS(metadata, _opeType, ex);
                CDOMonitor.MonitorTrace(metadata, start, _opeType, ex, null, dataId);
                CDOMonitor.MonitorDuration(metadata, (DateTime.Now - start).TotalMilliseconds, _opeType, ex);
            }
        }

        /// <summary>
        /// 获取对象数据
        /// </summary>            
        /// <param name="metadata">元数据</param>
        /// <param name="childNodeId">节点ID</param>
        /// <param name="dataId">数据唯一标识</param>        
        /// <returns>通用结果对象</returns>
        public TResult QueryData(CompositeDataObject metaData, string childNodeId, string dataId, Dictionary<string, object> extParams = null)
        {
            if (metaData == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_MetaDataCannotBeNull);
            if (string.IsNullOrWhiteSpace(dataId))
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_DataIDCannotBeNull);

            var cno = metaData.CompositeNodeObjects.FirstOrDefault(i => i.ID == childNodeId);
            if (cno == null)
            {
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.CDOService_CannotFindCNOInstance + childNodeId);
            }

            var sqls = SQLBuilderFactory.CreateCDOSQLBuilder().ParseQuerySqlByID(metaData, cno, dataId);

            var datatable = ExecuteSQL(metaData, sqls);

            return TResultConverter.ConvertToTResultFromCDO(metaData, datatable, false);
        }

        #region Obsolete
        /// <summary>
        /// 综合查询数据
        /// </summary>        
        /// <param name="metaData">元数据</param>        
        /// <param name="queryFilter">查询条件</param>        
        /// <returns>通用结果对象</returns>
        [Obsolete("CDO本身不再支持类高级查询功能，请使用DQ")]
        public TResult QueryData(CompositeDataObject metaData, QueryFilter queryFilter, Dictionary<string, object> extParams = null)
        {
            if (metaData == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_MetaDataCannotBeNull);
            if (queryFilter == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_FilterCannotBeNull);

            var sqls = SQLBuilderFactory.CreateCDOSQLBuilder().ParseQuerySqlByFilter(metaData, queryFilter);

            var datatable = ExecuteSQL(metaData, sqls);

            return TResultConverter.ConvertToTResultFromCDO(metaData, datatable, true);
        }

        /// <summary>
        /// 获取对象数据
        /// </summary>        
        /// <param name="metaData">元数据</param>
        /// <param name="childNodeId">节点ID</param>
        /// <param name="queryFilter">查询条件</param>
        /// <returns>通用结果对象</returns>
        [Obsolete("CDO本身不再支持类高级查询功能，请使用DQ")]
        public TResult QueryData(CompositeDataObject metaData, string childNodeId, QueryFilter queryFilter, Dictionary<string, object> extParams = null)
        {
            if (metaData == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_MetaDataCannotBeNull);
            if (queryFilter == null)
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.DataModelService_FilterCannotBeNull);

            var cno = metaData.CompositeNodeObjects.FirstOrDefault(i => i.ID == childNodeId);
            if (cno == null)
            {
                throw new FasException(DataAccessErrorCode.CompositeDataObject.NullValue, CommonStringClassEngine.CDOService_CannotFindCNOInstance + childNodeId);
            }

            var sqls = SQLBuilderFactory.CreateCDOSQLBuilder().ParseQuerySqlByFilter(metaData, cno, queryFilter);

            var datatable = ExecuteSQL(metaData, sqls);

            return TResultConverter.ConvertToTResultFromCDO(metaData, datatable, true);
        }

        #endregion

        /// <summary>
        /// 统一执行SQL，提供友好性报错提示
        /// </summary>
        /// <param name="metaData"></param>
        /// <param name="sqls"></param>
        /// <returns></returns>
        private List<DataTable> ExecuteSQL(CompositeDataObject metaData, SqlStatementCollection sqls)
        {
            try
            {
                var datatable = _db.GetDataCollection(sqls);
                return datatable;
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.CompositeDataObject.Error, string.Format(CommonStringClassEngine.CDODataQueryService_ExecuteSQL, metaData?.Code), e);
            }
        }
    }
}
